home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
GraphicViewers
/
ViewGif2
/
Source
/
LZWDecoder.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-21
|
13KB
|
398 lines
/***************************************************************************/
/* LZWDecode.c - source code for LZW decoding of GIF files */
/* Used in ViewGif2 Application */
/* This is not very elegant code, but it allows the decoding to be broken */
/* up into arbitrary pieces, thus being nice to system resources */
/* January 1990 Carl F. Sutter */
/***************************************************************************/
#include <stdio.h>
#include <streams/streams.h>
/* some global data types and constants */
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
#define BOOL int
#define TRUE 1
#define FALSE 0
#define MAXCODES 4096
/* LZW variables */
WORD wCodeClear;
WORD wCodeEOI;
WORD wCodeLength;
WORD wTablePointer;
WORD wCurrentTablePointerMax;
/* LZW stack implementation */
BYTE byStack[MAXCODES];
WORD wStackPointer;
WORD wFirstCode[MAXCODES];
WORD wSecondCode[MAXCODES];
BYTE byCodeSize;
long lNumPixelsDecoded;
/* functions in this code */
void StartLZW( BYTE byCodeSizeIn, NXStream *stream,
BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
int width, int height, BOOL bInter );
long ContinueLZW( int nNumCodes );
void InitializeLZWTable( void );
BOOL ReadNextCode( BOOL bInitialize, WORD *wCode );
BOOL FillStack( WORD wCode );
BOOL AddToTable( WORD wFirst, WORD wSecond );
WORD FirstCode( WORD wCode );
BOOL IsInTable( WORD wCode, BOOL *bResult );
BOOL ReadNextDataByte( NXStream *stream, BYTE *byReturn );
BOOL WriteStack( BYTE byStack[], WORD *wPointer,
BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
int width, int height, BOOL bInter );
/***************************************************************************/
/* StartLZW - handle all initialization of the LZW dedcoder */
/***************************************************************************/
void StartLZW( BYTE byCodeSizeIn, NXStream *stream,
BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
int width, int height, BOOL bInter )
{
/* save input parameters */
byCodeSize = byCodeSizeIn;
/* set the constant clear and EOI codes, and the pixel count */
wCodeClear = 1;
wCodeClear <<= byCodeSize; /* Clear Code = 2^CodeSize */
wCodeEOI = wCodeClear + 1;
lNumPixelsDecoded = 0;
/* initialize the following functions */
ReadNextCode( TRUE, NULL );
ReadNextDataByte( stream, NULL );
WriteStack( NULL, NULL, byR, byG, byB, byMap, width, height, bInter );
/* set the LZW values in case the first code is not a clear code */
InitializeLZWTable();
} /* StartLZW 1/24/90 CFS */
/***************************************************************************/
/* ContinueLZW - keep decoding the LZW encoded data stream */
/***************************************************************************/
long ContinueLZW( int nNumCodes )
{
static WORD wCode, wOldCode;
int nNumCodesRead;
BOOL bInTable;
nNumCodesRead = 0;
while ( (nNumCodesRead < nNumCodes) && (ReadNextCode( FALSE, &wCode )) &&
(wCode != wCodeEOI) )
{
nNumCodesRead++;
if (wCode == wCodeClear)
{
InitializeLZWTable();
if (!ReadNextCode( FALSE, &wCode )) break;
if (wCode == wCodeEOI) break;
nNumCodesRead++;
if (!FillStack( wCode )) break;
}
else /* not clear code */
{
if (!IsInTable( wCode, &bInTable )) break;
if (bInTable)
{
if (!FillStack( wCode )) break;
if (!AddToTable( wOldCode, FirstCode( wCode ) )) break;
}
else /* code is not in table */
{
if (!FillStack( wOldCode )) break;
if (!FillStack( FirstCode( wOldCode ) )) break;
if (!AddToTable( wOldCode, FirstCode( wOldCode ) )) break;
}
} /* not clear code */
wOldCode = wCode;
} /* while loop */
/* return value depends on clean codes up to EOI */
/* note: even if errors were found, some of the image may be OK */
if (wCode == wCodeEOI) return( 0 );
if (nNumCodesRead == nNumCodes) return( lNumPixelsDecoded );
/* else something went wrong, signal caller to quit */
return( -1 );
} /* LZWDecode 10/16/89 CFS */
/***************************************************************************/
/* InitializeLZWTable - init the table and global pointers and counters */
/***************************************************************************/
void InitializeLZWTable( void )
{
wCodeLength = byCodeSize + 1;
wCurrentTablePointerMax = 1; /* wCurrentTablePointer = */
wCurrentTablePointerMax <<= wCodeLength; /* 2^wCodeLength */
wTablePointer = wCodeEOI + 1;
} /* InitializeLZWTable 10/5/89 CFS */
/***************************************************************************/
/* ReadNextCode - get the next LZW code from the file */
/***************************************************************************/
BOOL ReadNextCode( BOOL bInitialize, WORD *wCode )
{
static WORD wMask[] = { 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F,
0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF };
static DWORD dwStorage;
static BYTE byBitsAvail;
WORD wNextCode;
BYTE byNextByte;
/* initialize if requested */
if (bInitialize == TRUE)
{
dwStorage = 0;
byBitsAvail = 0;
return( TRUE );
}
/* get enough data in the storage variable to handle the request */
while ((WORD)byBitsAvail < wCodeLength)
{
if (!ReadNextDataByte( NULL, &byNextByte )) return( FALSE );
dwStorage |= (DWORD)byNextByte << (DWORD)byBitsAvail;
byBitsAvail += 8;
}
/* now get the bits for the new code, and shift out the used bits */
wNextCode = (WORD)(dwStorage & (DWORD)wMask[wCodeLength - 1]);
dwStorage >>= (DWORD)wCodeLength;
byBitsAvail -= (BYTE)wCodeLength;
*wCode = wNextCode;
return( TRUE );
} /* ReadNextCode 10/5/89 CFS */
/***************************************************************************/
/* FillStack - start with the given code, and put colors on the stack */
/***************************************************************************/
BOOL FillStack( WORD wCode )
{
wStackPointer = 0;
/* check first whether the code is just a pixel color */
if (wCode < wCodeClear)
byStack[wStackPointer++] = (BYTE)wCode;
/* make sure the code is in a valid range */
else if ((wCode <= wCodeEOI) || (wCode >= wTablePointer))
{
fprintf( stderr,
"ViewGif LZWDecode error - FillStack code is not a valid table entry.\n" );
return( FALSE );
}
/* the code is from the table, trace the codes and collect pixels */
else
{
while (wFirstCode[wCode] > wCodeClear)
{
byStack[wStackPointer++] = (BYTE)wSecondCode[wCode];
wCode = wFirstCode[wCode];
}
byStack[wStackPointer++] = (BYTE)wSecondCode[wCode];
byStack[wStackPointer++] = (BYTE)wFirstCode[wCode];
}
/* all went well, so pop the stack of pixels into the bitmap buffers */
return( WriteStack( byStack, &wStackPointer,
(BYTE *)NULL, (BYTE *)NULL, (BYTE *)NULL, (BYTE *)NULL,
(int)NULL, (int)NULL, (BOOL)NULL ) );
} /* FillStack 10/6/89 CFS */
/***************************************************************************/
/* AddToTable - add the code to the tables */
/***************************************************************************/
BOOL AddToTable( WORD wFirst, WORD wSecond )
{
/* save data at the wTablePointer location */
wFirstCode[wTablePointer] = wFirst;
wSecondCode[wTablePointer] = wSecond;
/* increment the table pointer */
wTablePointer++;
if (wTablePointer > MAXCODES)
{
fprintf( stderr, "ViewGif LZWDecode error - LZW table up to 4095\n" );
return( FALSE );
}
/* if the table pointer is about to exceed the code length, up it */
if (wTablePointer == wCurrentTablePointerMax)
{
if (wCodeLength < 12) wCodeLength += 1;
wCurrentTablePointerMax = 1; /* wCurrentTablePointer = */
wCurrentTablePointerMax <<= wCodeLength; /* 2^wCodeLength */
}
return( TRUE );
} /* AddToTable 10/6/89 CFS */
/***************************************************************************/
/* FirstCode - trace the code back to it's first pixel color */
/***************************************************************************/
WORD FirstCode( WORD wCode )
{
/* check first whether the code is just a pixel color */
if (wCode < wCodeClear) return( wCode );
/* if not, trace back the first codes until it is a color */
while (wFirstCode[wCode] > wCodeClear)
wCode = wFirstCode[wCode];
return( wFirstCode[wCode] );
} /* FirstCode 10/5/89 CFS */
/***************************************************************************/
/* IsInTable - return true if the code is a pixel color, or in the table */
/***************************************************************************/
BOOL IsInTable( WORD wCode, BOOL *bResult )
{
/* check first whether the code is just a pixel color */
if (wCode < wCodeClear)
{
*bResult = TRUE;
return( TRUE );
}
/* make sure the code is not a special one, or bigger than the */
/* next table entry */
if ((wCode <= wCodeEOI) || (wCode > wTablePointer))
{
fprintf( stderr,
"ViewGif LZWDecode error - IsInTable code is not a valid table entry.\n" );
return( FALSE );
}
/* if the code will be the next table entry, OK, but return false */
if (wCode == wTablePointer)
{
*bResult = FALSE;
return( TRUE );
}
/* finally, the code must be already in the table EOI < code < TP */
*bResult = TRUE;
return( TRUE );
} /* IsInTable 10/5/89 CFS */
/***************************************************************************/
/* ReadNextDataByte - get the next image data byte from the file */
/***************************************************************************/
BOOL ReadNextDataByte( NXStream *stream, BYTE *byReturn )
{
#define MAX_BLOCK_SIZE 255
static BYTE byBlockSize = 0;
static BYTE byData[MAX_BLOCK_SIZE];
static NXStream *fileStream;
static BYTE byLeft;
int nError;
/* if the stream is not NULL, initialize this function */
if (stream != NULL)
{
byLeft = 0;
fileStream = stream;
return( TRUE );
}
/* get the next block of data if necessary */
if (byLeft == 0)
{
nError = NXRead( fileStream, &byBlockSize, 1 );
if (nError <= 0)
{
fprintf( stderr,
"ViewGif2 LZWDecode error - ReadNextDataByte unexpected end of file.\n" );
return( FALSE );
}
byLeft = byBlockSize;
nError = NXRead( fileStream, byData, byBlockSize );
if (nError <= 0)
{
fprintf( stderr,
"ViewGif2 LZWDecode error - ReadNextDataByte unexpected end of file.\n" );
return( FALSE );
}
}
/* return the data byte and decrement the number left */
*byReturn = byData[byBlockSize - byLeft--];
return( TRUE );
} /* ReadNextDataByte 10/16/89 CFS */
/***************************************************************************/
/* WriteStack - pop the pixel stack and color in the pixels */
/***************************************************************************/
BOOL WriteStack( BYTE byStack[], WORD *wPointer,
BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
int width, int height, BOOL bInter )
{
static int nLines[] = { 0, 4, 2, 1 };
static int nJump[] = { 8, 8, 4, 2 };
int nColorIndex;
DWORD dwDataIndex;
static BYTE *byDataR, *byDataG, *byDataB;
static BYTE *byColorMap;
static int nWidth, nHeight;
static BOOL bInterlaced;
static DWORD dwCurX, dwCurY;
static int nCurInterlace;
/* initialize the function if the stack is NULL */
if (byStack == NULL)
{
byDataR = byR; byDataG = byG; byDataB = byB;
byColorMap = byMap;
nWidth = width; nHeight = height;
bInterlaced = bInter;
dwCurX = dwCurY = 0;
nCurInterlace = 0;
return( TRUE );
}
while (*wPointer > 0)
{
(*wPointer)--;
lNumPixelsDecoded++;
/* put the pixel color in the data arrays */
nColorIndex = (int)byStack[*wPointer] * 3;
dwDataIndex = dwCurY * (long)nWidth + dwCurX;
byDataR[dwDataIndex] = byColorMap[ nColorIndex];
byDataG[dwDataIndex] = byColorMap[++nColorIndex];
byDataB[dwDataIndex] = byColorMap[++nColorIndex];
/* increment the counters */
if (++dwCurX == nWidth)
{
dwCurX = 0;
if (bInterlaced)
{
dwCurY += nJump[nCurInterlace];
if (dwCurY>=nHeight)
dwCurY = nLines[++nCurInterlace];
}
else dwCurY++;
}
}
return( TRUE );
} /* WriteStack 10/16/89 CFS */